package cn.iocoder.yudao.framework.excel.core.util;

import cn.iocoder.yudao.framework.common.util.http.HttpUtils;
import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.math.BigInteger;
import java.util.List;

/**
 * Word 工具类，用于将数据导出为 Word 文档表格格式
 *
 * @author 芋道源码
 */
public class WordUtils {

    /**
     * 将列表以 Word 文档响应给前端
     *
     * @param response  响应
     * @param filename  文件名
     * @param head      Excel head 头
     * @param data      数据列表
     * @param <T>       泛型，保证 head 和 data 类型的一致性
     * @throws IOException 写入失败的情况
     */
    public static <T> void write(HttpServletResponse response, String filename,
                                 Class<T> head, List<T> data) throws IOException {
        // 创建 Word 文档
        XWPFDocument document = new XWPFDocument();
        
        // 创建标题段落
        XWPFParagraph titleParagraph = document.createParagraph();
        titleParagraph.setAlignment(ParagraphAlignment.CENTER);
        XWPFRun titleRun = titleParagraph.createRun();
        titleRun.setText(filename.replace(".docx", ""));
        titleRun.setBold(true);
        titleRun.setFontSize(16);
        
        // 添加一个空行
        XWPFParagraph emptyParagraph = document.createParagraph();
        XWPFRun emptyRun = emptyParagraph.createRun();
        emptyRun.setText("");
        
        // 创建表格
        XWPFTable table = document.createTable();
        
        // 设置表格样式
        setTableStyle(table);
        
        // 获取表头字段
        Field[] fields = head.getDeclaredFields();
        
        // 创建表头行
        XWPFTableRow headerRow = table.getRow(0);
        createHeaderRow(headerRow, fields);
        
        // 填充数据行
        for (T item : data) {
            XWPFTableRow dataRow = table.createRow();
            fillDataRow(dataRow, fields, item);
        }
        
        // 自动调整表格列宽
        setTableWidth(table, fields.length);
        
        // 输出 Word 文档
        OutputStream out = response.getOutputStream();
        document.write(out);
        out.close();
        document.close();
        
        // 设置 header 和 contentType
        response.addHeader("Content-Disposition", "attachment;filename=" + HttpUtils.encodeUtf8(filename));
        response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document;charset=UTF-8");
    }

    /**
     * 设置表格样式
     * 
     * @param table Word表格
     */
    private static void setTableStyle(XWPFTable table) {
        // 设置表格宽度
        table.setWidth("100%");
        
        // 设置表格边框
        CTTblBorders borders = CTTblBorders.Factory.newInstance();
        borders.addNewTop().setVal(STBorder.SINGLE);
        borders.addNewLeft().setVal(STBorder.SINGLE);
        borders.addNewBottom().setVal(STBorder.SINGLE);
        borders.addNewRight().setVal(STBorder.SINGLE);
        borders.addNewInsideH().setVal(STBorder.SINGLE);
        borders.addNewInsideV().setVal(STBorder.SINGLE);
        
        // 应用边框到表格
        CTTblPr tblPr = table.getCTTbl().getTblPr();
        if (tblPr == null) {
            tblPr = table.getCTTbl().addNewTblPr();
        }
        tblPr.setTblBorders(borders);
    }

    /**
     * 设置表格列宽
     * 
     * @param table 表格
     * @param columnCount 列数
     */
    private static void setTableWidth(XWPFTable table, int columnCount) {
        // 设置每列的宽度
        int tableWidth = 8000; // 总宽度
        int columnWidth = tableWidth / columnCount; // 每列宽度
        
        for (XWPFTableRow row : table.getRows()) {
            for (XWPFTableCell cell : row.getTableCells()) {
                CTTcPr tcPr = cell.getCTTc().addNewTcPr();
                CTTblWidth tcw = tcPr.addNewTcW();
                tcw.setW(BigInteger.valueOf(columnWidth));
                tcw.setType(STTblWidth.DXA);
            }
        }
    }

    /**
     * 创建表头行
     * 
     * @param row    表格行
     * @param fields 字段数组
     */
    private static void createHeaderRow(XWPFTableRow row, Field[] fields) {
        for (int i = 0; i < fields.length; i++) {
            Field field = fields[i];
            field.setAccessible(true);
            
            // 获取字段上的 ExcelProperty 注解值作为表头名称
            String headerName = getExcelPropertyAnnotationValue(field);
            
            XWPFTableCell cell = row.getCell(i);
            if (cell == null) {
                cell = row.addNewTableCell();
            }
            
            // 设置表头单元格内容
            cell.setText(headerName != null ? headerName : field.getName());
            
            // 设置表头样式
            setHeaderCellStyle(cell);
        }
    }

    /**
     * 填充数据行
     * 
     * @param row    表格行
     * @param fields 字段数组
     * @param item   数据对象
     */
    private static void fillDataRow(XWPFTableRow row, Field[] fields, Object item) {
        for (int i = 0; i < fields.length; i++) {
            Field field = fields[i];
            field.setAccessible(true);
            
            XWPFTableCell cell = row.getCell(i);
            if (cell == null) {
                cell = row.addNewTableCell();
            }
            
            try {
                Object value = field.get(item);
                cell.setText(value != null ? value.toString() : "");
            } catch (IllegalAccessException e) {
                cell.setText("");
            }
            
            // 设置数据单元格样式
            setDataCellStyle(cell);
        }
    }

    /**
     * 获取字段上 ExcelProperty 注解的值
     * 
     * @param field 字段
     * @return 注解值
     */
    private static String getExcelPropertyAnnotationValue(Field field) {
        cn.idev.excel.annotation.ExcelProperty excelProperty = 
            field.getAnnotation(cn.idev.excel.annotation.ExcelProperty.class);
        if (excelProperty != null && excelProperty.value().length > 0) {
            return excelProperty.value()[0];
        }
        return null;
    }

    /**
     * 设置表头单元格样式
     * 
     * @param cell 单元格
     */
    private static void setHeaderCellStyle(XWPFTableCell cell) {
        // 设置背景色为浅灰色
        cell.setColor("D3D3D3");
        
        // 设置字体加粗
        for (XWPFParagraph paragraph : cell.getParagraphs()) {
            paragraph.setAlignment(ParagraphAlignment.CENTER); // 居中对齐
            for (XWPFRun run : paragraph.getRuns()) {
                run.setBold(true);
            }
        }
    }
    
    /**
     * 设置数据单元格样式
     * 
     * @param cell 单元格
     */
    private static void setDataCellStyle(XWPFTableCell cell) {
        // 设置数据单元格内容居中对齐
        for (XWPFParagraph paragraph : cell.getParagraphs()) {
            paragraph.setAlignment(ParagraphAlignment.CENTER);
        }
    }
}